home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uniput.zip / DISPLAY.C next >
C/C++ Source or Header  |  1992-10-26  |  22KB  |  761 lines

  1. /**************************************************************************\
  2. *  display.c -- module to support the main MDI child windows.
  3. *
  4. *         Steve Firebaugh
  5. *         Microsoft Developer Support
  6. *         Copyright (c) 1992 Microsoft Corporation
  7. *
  8. * window class registered in uniput.c
  9. * windows are created in main frame window procedure.
  10. *
  11. * design:  We have one window procedure here for potentially multiple
  12. *  MDI child windows.  The nCharPerLine, SqrHeight, and SqrWidth are
  13. *  stored on a per window basis.  Also, the window class is registered
  14. *  with the style CS_OWNDC.  For this reason, it is possible to select
  15. *  a logical font into the HDC, and it will be there each time you get
  16. *  the DC new for the window.  In this way we have a log font for each
  17. *  window without actually doing any work in this module.
  18. *
  19. *  Some of the data is global, and works for all of the windows.  The
  20. *  startcount & endcount arrays are a good example.  These are computed
  21. *  once when the font is created, but the values remain the same for each
  22. *  window.  Thus we have the following assumption:
  23. *
  24. *   1.  No fonts will be installed or removed while program is running.
  25. *       (CountUCSegments values remain valid for run time duration).
  26. *
  27. *
  28. *  There are WM_USER+ messages to set values for this window, and to
  29. *  notify it of global changes.  Looking at the create time, user message
  30. *  stream is helpful.  On the WM_CREATE message, we send ourselves a
  31. *  WMU_NEWFONT message to create a logical font and count the number of
  32. *  character ranges (segments).  Before returning from this message, we
  33. *  send ourselves a WMU_NEWRANGE message to set the title, and the
  34. *  horizontal scroll bar correctly.
  35. *
  36. *
  37. \**************************************************************************/
  38. #define UNICODE
  39.  
  40. #include <windows.h>
  41. #include "uniput.h"
  42.  
  43.  
  44. /* global variables store the start and end codepoints for UC ranges. */
  45. #define MAXSEGMENTS  100
  46. USHORT endCount[MAXSEGMENTS];
  47. USHORT startCount[MAXSEGMENTS];
  48.  
  49. int CountUCSegments (HDC);
  50. /* error return value from CountUCSegments */
  51. #define SEGMENTERROR -1
  52.  
  53.  
  54. /* conversion between (x,y) pairs and rectangle index */
  55. int transXYtoIndex (int, int, int, int, int);
  56. int transIndextoRect (int, PRECT, int, int, int);
  57.  
  58.  
  59. /* window extra bytes for use to store window specific data (see register class) */
  60. #define GWLU_NCHAR        0
  61. #define GWLU_SQRHEIGHT    4
  62. #define GWLU_SQRWIDTH     8
  63.  
  64.  
  65.  
  66. /* structure for the character range 'name' lookup table.  */
  67. typedef struct tagLookupEntry{
  68.     USHORT   start;
  69.     USHORT   end;
  70.     TCHAR    String[32];
  71. } LookupEntry;
  72.  
  73. /* The following data comes straight out of the Addison-Wesley Unicode book. */
  74. #define NRANGE 24
  75. LookupEntry  RangeName[NRANGE] =
  76.     {{ 0x0000,0x007f, TEXT("ASCII")},
  77.      { 0x0080,0x00ff, TEXT("Latin1 Characters")},
  78.      { 0x0100,0x017f, TEXT("European Latin")},
  79.      { 0x0180,0x01ff, TEXT("Extended Latin")},
  80.      { 0x0200,0x024f, TEXT("<Bad unicode range.>")},
  81.      { 0x0250,0x02af, TEXT("Standard Phonetic")},
  82.      { 0x02b0,0x02ff, TEXT("Modifier Letters")},
  83.      { 0x0300,0x036f, TEXT("Generic Diacritical Marks")},
  84.      { 0x0370,0x03ff, TEXT("Greek")},
  85.      { 0x0400,0x04ff, TEXT("Cyrillic")},
  86.      { 0x0500,0x052f, TEXT("<Bad unicode range.>")},
  87.      { 0x0530,0x058f, TEXT("Armenian")},
  88.      { 0x0590,0x05ff, TEXT("Hebrew")},
  89.      { 0x0600,0x06ff, TEXT("Arabic")},
  90.      { 0x0900,0x1fff, TEXT("<not specified in table.>")},
  91.      { 0x2000,0x206f, TEXT("General Punctutation")},
  92.      { 0x2070,0x209f, TEXT("Superscipts & Subscripts")},
  93.      { 0x20a0,0x20cf, TEXT("Currency Symbols")},
  94.      { 0x20d0,0x20ff, TEXT("Diacritical Marks for Symbols")},
  95.      { 0x2100,0x214f, TEXT("Letterlike Symbols")},
  96.      { 0x2150,0x218f, TEXT("Number Forms")},
  97.      { 0x2190,0x21ff, TEXT("Arrows")},
  98.      { 0x2200,0x22ff, TEXT("Mathematical Operators")},
  99.      { 0x2300,0xffff, TEXT("<not specified in table.>")}};
  100.  
  101.  
  102.  
  103. /* Global logfont.  Used for CreateFontIndirect().
  104.  *  also regerenced in the uniput.c file.
  105.  */
  106. LOGFONT logfont = {
  107.       UCFONTHEIGHT ,
  108.       UCFONTWIDTH ,
  109.        0 ,
  110.        0 ,
  111.      400 ,
  112.        0 ,
  113.        0 ,
  114.        0 ,
  115.        UNICODE_CHARSET ,
  116.        0 ,
  117.        0 ,
  118.        2 ,
  119.        2 ,
  120.       TEXT("Lucida Sans Unicode")};
  121.  
  122.  
  123.  
  124.  
  125.  
  126. /**************************************************************************\
  127. *
  128. *  function:  DisplayWndProc()
  129. *
  130. *  input parameters:  normal window procedure parameters.
  131. *
  132. \**************************************************************************/
  133. LRESULT CALLBACK DisplayWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  134. {
  135. static HFONT  hfont, hfontOld;
  136.  
  137. static HDC hdc;
  138. static RECT rect;
  139. static int iSeg;
  140. static TCHAR buffer[100];
  141.  
  142. /* rDown and index used as the user points to a square. */
  143. static RECT rDown;
  144. static int index;
  145.  
  146.  
  147.   switch (message) {
  148.  
  149.     /**********************************************************************\
  150.     *  WM_CREATE
  151.     *
  152.     * Create font.
  153.     \**********************************************************************/
  154.     case WM_CREATE:
  155.       SendMessage (hwnd, WMU_SETNCHAR, 16, 0);
  156.       SendMessage (hwnd, WMU_NEWFONT, (WPARAM) logfont.lfWidth, (LPARAM) logfont.lfHeight);
  157.     break;
  158.  
  159.  
  160.     /**********************************************************************\
  161.     *  WM_DESTROY
  162.     *
  163.     * Get rid of the logical font we create for each display window.
  164.     *  relying here on CS_ONWDC
  165.     \**********************************************************************/
  166.     case WM_DESTROY:
  167.       hdc = GetDC (hwnd);
  168.       hfont = SelectObject  (hdc, GetStockObject(SYSTEM_FONT));
  169.       ReleaseDC (hwnd, hdc);
  170.       DeleteObject (hfont);
  171.  
  172.     break;
  173.  
  174.  
  175.  
  176.  
  177.  
  178.     /**********************************************************************\
  179.     *  WMU_SETNCHAR
  180.     *
  181.     * wParam - nCharPerLine
  182.     *
  183.     \**********************************************************************/
  184.     case WMU_SETNCHAR:
  185.       SetWindowLong (hwnd, GWLU_NCHAR, (int) wParam);
  186.       InvalidateRect (hwnd, NULL, TRUE);
  187.     break;
  188.  
  189.     /**********************************************************************\
  190.     *  WMU_NEWFONT
  191.     *
  192.     * wParam - Width
  193.     * lParam - Height
  194.     *
  195.     * Create font, select it into the HDC, and reset ranges.
  196.     \**********************************************************************/
  197.     case WMU_NEWFONT: {
  198.       int nSegments;
  199.  
  200.       hdc = GetDC(hwnd);
  201.  
  202.       logfont.lfHeight = (int) lParam;
  203.       logfont.lfWidth  = (int) wParam;
  204.  
  205.       hfont = CreateFontIndirect (&logfont);
  206.       hfontOld = SelectObject (hdc, hfont);
  207.       DeleteObject (hfontOld);
  208.  
  209.       nSegments = CountUCSegments (hdc); /* slow computation */
  210.       ReleaseDC (hwnd, hdc);
  211.  
  212.  
  213.       /* verify that we have SOME ranges to work with */
  214.       if (nSegments == SEGMENTERROR) return FALSE;
  215.  
  216.       /* warn the user if we can't find the right font */
  217.       if (nSegments < 30)
  218.         MessageBox (hwnd,
  219.             TEXT("Working w/ limited codepoint coverage."),
  220.             TEXT("Lucida Sans Unicode font not found."), MB_OK);
  221.  
  222.  
  223.  
  224.       SetScrollRange (hwnd, SB_HORZ, 0, (nSegments-1), TRUE);
  225.       SetScrollPos (hwnd, SB_HORZ, 0, TRUE);
  226.  
  227.       SendMessage (hwnd, WMU_NEWRANGE, 0,0);
  228.  
  229.     } return TRUE;
  230.  
  231.  
  232.     /**********************************************************************\
  233.     *  WMU_NEWRANGE
  234.     *
  235.     *
  236.     * Range changes, or font size changes, or title status changes.
  237.     \**********************************************************************/
  238.     case WMU_NEWRANGE: {
  239.       int sqrHeight, sqrWidth;
  240.       TEXTMETRIC tm;
  241.       int i;
  242.  
  243.       hdc = GetDC(hwnd);
  244.       GetTextMetrics (hdc, &tm);
  245.       ReleaseDC (hwnd, hdc);
  246.  
  247.       /* index into the start, end arrays stored in scroll bar */
  248.       iSeg = GetScrollPos (hwnd, SB_HORZ);
  249.  
  250.       /* Set the window title text to show display range. */
  251.       wsprintf (buffer, TEXT("[%04x, %04x]"),
  252.                                   (int)startCount[iSeg],
  253.                                   (int)endCount[iSeg]);
  254.  
  255.       /* if we are supposed to look up the character range name,
  256.        *  then step through the ranges stored in the RangeName
  257.        *  table.  Find the correct one, and reset the buffer string.
  258.        */
  259.       if (gShowNames) {
  260.         for (i = 0; i< NRANGE; i++) {
  261.           if ((RangeName[i].start <= startCount[iSeg]) &&
  262.               ( startCount[iSeg] <= RangeName[i].end))
  263.  
  264.             wsprintf (buffer, TEXT("%s [%04x, %04x]"),
  265.                                   RangeName[i].String,
  266.                                   (int)startCount[iSeg],
  267.                                   (int)endCount[iSeg]);
  268.  
  269.         }
  270.       }
  271.       SetWindowText (hwnd, buffer);
  272.  
  273.       sqrHeight =  tm.tmHeight + tm.tmExternalLeading;
  274.       sqrWidth = tm.tmMaxCharWidth;
  275.  
  276.       SetWindowLong (hwnd, GWLU_SQRHEIGHT,sqrHeight);
  277.       SetWindowLong (hwnd, GWLU_SQRWIDTH, sqrWidth );
  278.  
  279.     } return TRUE;
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.     /**********************************************************************\
  290.     \**********************************************************************/
  291.     case WM_LBUTTONDOWN: {
  292.       int x,y;
  293.       int nCharPerLine;
  294.       int sqrHeight, sqrWidth;
  295.       nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
  296.       sqrHeight    = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
  297.       sqrWidth     = GetWindowLong (hwnd, GWLU_SQRWIDTH );
  298.  
  299.  
  300.  
  301.       x = (int)LOWORD (lParam);
  302.       y = (int)HIWORD (lParam);
  303.  
  304.       index = transXYtoIndex (x,y, sqrWidth, sqrHeight, nCharPerLine);
  305.  
  306.       /* verify that the index is within the shown segment range */
  307.       iSeg= GetScrollPos (hwnd, SB_HORZ);
  308.       if (index > (endCount[iSeg]- startCount[iSeg])) return NULL;
  309.  
  310.  
  311.       transIndextoRect (index, &rDown, sqrWidth, sqrHeight, nCharPerLine);
  312.  
  313.       hdc = GetDC (hwnd);
  314.       InvertRect (hdc, &rDown);
  315.       ReleaseDC (hwnd, hdc);
  316.  
  317.       GdiFlush ();
  318.       SetCapture (hwnd);
  319.     } break;
  320.  
  321.     /**********************************************************************\
  322.     *
  323.     * rDown & index set in WM_LBUTTONDOWN
  324.     *
  325.     \**********************************************************************/
  326.     case WM_LBUTTONUP: {
  327.       POINT p;
  328.  
  329.  
  330.       if (GetCapture() == hwnd) {
  331.  
  332.         p.x = (int)LOWORD (lParam);
  333.         p.y = (int)HIWORD (lParam);
  334.  
  335.         if (PtInRect (&rDown, p)) {
  336.           iSeg= GetScrollPos (hwnd, SB_HORZ);
  337.           index += startCount[iSeg];
  338.           Beep (40,40);
  339.           SendMessage (hwndMain, WMU_CHARACTER, 0, (LPARAM) index);
  340.         }
  341.  
  342.         hdc = GetDC (hwnd);
  343.         InvertRect (hdc, &rDown);
  344.         ReleaseDC (hwnd, hdc);
  345.         GdiFlush ();
  346.         ReleaseCapture ();
  347.  
  348.       }
  349.     } break;
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.     /**********************************************************************\
  357.     *  WM_HSCROLL
  358.     *
  359.     * Step through the character ranges.
  360.     * In every case, inform the window the range has changed,
  361.     *  and invalidate it to force a repaint.
  362.     \**********************************************************************/
  363.     case WM_HSCROLL:
  364.  
  365.       switch (LOWORD(wParam)){
  366.         int OldPos, NewPos;
  367.  
  368.         case SB_PAGEDOWN:
  369.         case SB_LINEDOWN:
  370.           OldPos = GetScrollPos (hwnd, SB_HORZ);
  371.           SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE);
  372.           SendMessage (hwnd,WMU_NEWRANGE, 0,0);
  373.           InvalidateRect (hwnd, NULL, TRUE);
  374.         break;
  375.  
  376.         case SB_PAGEUP:
  377.         case SB_LINEUP:
  378.           OldPos = GetScrollPos (hwnd, SB_HORZ);
  379.           SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE);
  380.           SendMessage (hwnd,WMU_NEWRANGE, 0,0);
  381.           InvalidateRect (hwnd, NULL, TRUE);
  382.         break;
  383.  
  384.         case SB_THUMBPOSITION:
  385.           OldPos = GetScrollPos (hwnd, SB_HORZ);
  386.           NewPos = HIWORD (wParam);
  387.           SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE);
  388.           SendMessage (hwnd,WMU_NEWRANGE, 0,0);
  389.           InvalidateRect (hwnd, NULL, TRUE);
  390.         break;
  391.  
  392.       }
  393.  
  394.     break;
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.     /**********************************************************************\
  403.     *  WM_SIZE
  404.     *
  405.     \**********************************************************************/
  406.     case WM_SIZE:
  407.       /* make sure that scroll metrics are ok */
  408.       SendMessage (hwnd, WMU_NEWRANGE, 0,0);
  409.  
  410.     break;  /* fall through to MDIChildProc */
  411.  
  412.  
  413.     /**********************************************************************\
  414.     *  WM_PAINT
  415.     *
  416.     \**********************************************************************/
  417.     case WM_PAINT: {
  418.       HDC hdc;
  419.       PAINTSTRUCT ps;
  420.       RECT rect;
  421.       POINT  point;
  422.       int i;
  423.       USHORT start, end;
  424.       WCHAR outChar;
  425.       USHORT codepoint;
  426.       int nCharPerLine;
  427.       int sqrHeight, sqrWidth;
  428.       nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
  429.       sqrHeight    = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
  430.       sqrWidth     = GetWindowLong (hwnd, GWLU_SQRWIDTH );
  431.  
  432.  
  433.       hdc = BeginPaint(hwnd, &ps);
  434.       SetBkMode (hdc, TRANSPARENT);
  435.  
  436.       iSeg= GetScrollPos (hwnd, SB_HORZ);
  437.       start = startCount[iSeg];
  438.       end = endCount[iSeg];
  439.  
  440.       /* ensure that we are in a valid range... some fonts have problems */
  441.       if (start != 0xffff)
  442.  
  443.         for (codepoint = start, i=0; codepoint<=end; codepoint++,i++) {
  444.  
  445.           /* paint box and frame it */
  446.           transIndextoRect (i, &rect, sqrWidth, sqrHeight, nCharPerLine);
  447.           InflateRect (&rect, -1, -1);
  448.           FillRect (hdc, &rect, GetStockObject (LTGRAY_BRUSH));
  449.           InflateRect (&rect, 1, 1);
  450.           FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH));
  451.           InflateRect (&rect, -1, -1);
  452.           SelectObject (hdc, GetStockObject (WHITE_PEN));
  453.           MoveToEx (hdc, rect.right, rect.top, NULL);
  454.           LineTo (hdc,rect.left, rect.top);
  455.           LineTo (hdc,rect.left, rect.bottom);
  456.  
  457.  
  458.  
  459.           /* set point that we will draw glyph at */
  460.           point.x = (rect.right + rect.left)/2;
  461.           point.y = rect.top;
  462.           SetTextAlign (hdc, TA_CENTER | TA_TOP);
  463.           SetTextColor (hdc, PALETTEINDEX (0));
  464.  
  465.  
  466.           /* special case the non-spacing diacritic marks. U+0300 -> U+036F
  467.            *  Write a space first, for them to 'modify.'
  468.            */
  469.           if ( (0x0300 <= codepoint) && (codepoint <= 0x036F) ) {
  470.             outChar = (WCHAR) 0x0020;
  471.             TextOutW (hdc, 0,0, &outChar, 1);
  472.           }
  473.  
  474.           outChar = (WCHAR) codepoint;
  475.           ExtTextOut(hdc, point.x, point.y, ETO_CLIPPED, &rect, (LPCTSTR)&outChar, 1, NULL);
  476.  
  477.  
  478.  
  479.           /* fill in unicode code point in hex */
  480.           if (gShowhex) {
  481.             int nchar;
  482.             HANDLE hfonttemp;
  483.  
  484.             nchar = wsprintf (buffer, TEXT("%04x"), (int) codepoint);
  485.             hfonttemp = SelectObject (hdc,GetStockObject (SYSTEM_FIXED_FONT));
  486.  
  487.             point.y = rect.bottom;
  488.             SetTextAlign (hdc, TA_CENTER | TA_BOTTOM);
  489.             SetTextColor (hdc, PALETTEINDEX (5));
  490.  
  491.             TextOut( hdc, point.x, point.y,
  492.                           buffer, nchar);
  493.             SelectObject (hdc,hfonttemp);
  494.           }
  495.  
  496.  
  497.         } /* end for */
  498.  
  499.       EndPaint (hwnd, &ps);
  500.     } return FALSE; /* end WM_PAINT */
  501.  
  502.  
  503.  
  504.  
  505.   } /* end switch */
  506.  
  507.   return (DefMDIChildProc(hwnd, message, wParam, lParam));
  508. }
  509.  
  510.  
  511.  
  512.  
  513. /**************************************************************************\
  514. *
  515. * Need a mapping between the (x,y) pair, and the index of the square on
  516. *  the window.  Two routines provide this... one for each direction.
  517. *
  518. \**************************************************************************/
  519.  
  520. /**********************************************************************\
  521. *  transXYtoIndex
  522. *
  523. *  Given x & y values, return the index.
  524. *
  525. \**********************************************************************/
  526. int transXYtoIndex (int x, int y,
  527.      int sqrWidth, int sqrHeight, int nCharPerLine)
  528. {
  529.     x /= sqrWidth;
  530.     if (x < 0) x = 0;
  531.     if (x >= nCharPerLine) x = nCharPerLine-1;
  532.  
  533.     y /= sqrHeight;
  534.     if (y < 0) y = 0;
  535.  
  536.     return ( (y * nCharPerLine) + x);
  537. }
  538.  
  539.  
  540. /**********************************************************************\
  541. *  transIndextoRect
  542. *
  543. *  Given an index, i.e. the number of one of the squares on the display
  544. *   window, fill in the rectangle structure.
  545. *
  546. \**********************************************************************/
  547. int transIndextoRect (int index, PRECT pr,
  548.      int sqrWidth, int sqrHeight, int nCharPerLine)
  549. {
  550. int x,y;
  551.  
  552.     x = index % nCharPerLine;
  553.     y = index / nCharPerLine;
  554.  
  555.     pr->left = x*sqrWidth;
  556.     pr->top = y*sqrHeight;
  557.     pr->right = pr->left +sqrWidth;
  558.     pr->bottom = pr->top +sqrHeight;
  559.  
  560.     return TRUE;
  561. }
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568. /**************************************************************************\
  569. *
  570. * All of the code below is used for parsing 'font data.'  It will only
  571. *  make sense if you have a copy of the True Type font spec.  In short,
  572. *  we grab the 'cmap' table, look through it for a subtable, and then
  573. *  get two parallel arrays from the subtable.  Complications arise because
  574. *  the true type data is 'BIG ENDIAN' and NT is being run 'little endian.'
  575. *  For this reason, once we locate the short or long, we call Swap* to
  576. *  change the byte ordering.
  577. *
  578. \**************************************************************************/
  579.  
  580.  
  581. VOID SwapShort (PUSHORT);
  582. VOID SwapULong  (PULONG);
  583.  
  584.  
  585.  
  586. typedef struct tagTABLE{
  587.     USHORT platformID;
  588.     USHORT encodingID;
  589.     ULONG  offset;
  590. } TABLE, *PTABLE;
  591.  
  592. typedef struct tagSUBTABLE{
  593.     USHORT format;
  594.     USHORT length;
  595.     USHORT version;
  596.     USHORT segCountX2;
  597.     USHORT searchRange;
  598.     USHORT entrySelector;
  599.     USHORT rangeShift;
  600. } SUBTABLE, *PSUBTABLE;
  601.  
  602.  
  603. /* 'cmap' is passed in by value in a DWORD */
  604. #define CMAPHEX  0x636d6170
  605. #define NBYTES   256
  606. #define OFFSETERROR  0
  607.  
  608.  
  609.  
  610. /**************************************************************************\
  611. *
  612. *  function:  CountUCSegments()
  613. *
  614. *  input parameters:
  615. *   hdc - with the logical font set into it.
  616. *   prect - pointer to client rectangle.
  617. *
  618. *  Global variables:
  619. *   startCount
  620. *   endCount
  621. *
  622. *  returns:
  623. *   number of UC segments or
  624. *   SEGMENTERROR if there is some kind of error.
  625. *
  626. *  essential side effect:
  627. *   Fills in global startCount, endCount arrays.
  628. \**************************************************************************/
  629. int CountUCSegments (HDC hdc)
  630. {
  631. DWORD       cbData;
  632. USHORT      aShort[2];
  633. DWORD       nBytes;
  634. USHORT      i, nTables;
  635. PTABLE      pTable;
  636. PSUBTABLE   pSubTable;
  637. ULONG       offset,offsetFormat4;
  638. USHORT      segCount;
  639. BYTE        buffer[NBYTES];
  640.  
  641.  
  642.  
  643.  
  644.     /* find number of 'subtables', second long in cmap */
  645.     nBytes=GetFontData (hdc, CMAPHEX, 0, aShort, 4);
  646.     if (nBytes == (DWORD)-1) {
  647.       MessageBox (NULL, MBGETFONTDATAERR,MBERROR , MBERRORFLAGS);
  648.       return SEGMENTERROR;
  649.     }
  650.     nTables = aShort[1];
  651.     SwapShort (&nTables);
  652.  
  653.  
  654.     cbData = nTables * sizeof(TABLE);
  655.     if (cbData >NBYTES) {
  656.       MessageBox (NULL, TEXT("cbData >NBYTES"),MBERROR , MBERRORFLAGS);
  657.       return SEGMENTERROR;
  658.     }
  659.  
  660.     /* get array of subtables information.  Check each one for 3,1*/
  661.     nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData);
  662.     pTable = (PTABLE)buffer;
  663.     offsetFormat4 = OFFSETERROR;
  664.     for (i = 0; i< nTables; i++) {
  665.  
  666.         SwapShort (&(pTable->encodingID));
  667.         SwapShort (&(pTable->platformID));
  668.  
  669.         if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) {
  670.           offsetFormat4 = pTable->offset;
  671.           SwapULong (&offsetFormat4);
  672.           break;
  673.         }
  674.         pTable++;
  675.     }
  676.  
  677.     /* verify that we got the correct offset to the FORMAT 4 subtable */
  678.     if (offsetFormat4 == OFFSETERROR){
  679.       MessageBox (NULL, TEXT("Can not find 3,1 subtable"),MBERROR , MBERRORFLAGS);
  680.       return SEGMENTERROR;
  681.     }
  682.  
  683.     /* Get the beginning of the subtable, especially the segment count */
  684.     nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE));
  685.     pSubTable = (PSUBTABLE) buffer;
  686.     SwapShort (&(pSubTable->format));
  687.     SwapShort (&(pSubTable->segCountX2));
  688.  
  689.     if (pSubTable->format != 4){
  690.       MessageBox (NULL, TEXT("format !=4"), MBERROR, MBERRORFLAGS);
  691.       return SEGMENTERROR;
  692.     }
  693.  
  694.     segCount = pSubTable->segCountX2 / 2;
  695.  
  696.     if (segCount > MAXSEGMENTS){
  697.       MessageBox (NULL, TEXT("segCount > MAXSEGMENTS"), MBERROR, MBERRORFLAGS);
  698.       return SEGMENTERROR;
  699.     }
  700.  
  701.     /* read in the array of endCount values */
  702.     offset = offsetFormat4
  703.            + (7 * sizeof (USHORT));  /* skip constant # bytes in subtable */
  704.     cbData = segCount * sizeof (USHORT);
  705.     nBytes=GetFontData (hdc, CMAPHEX, offset, endCount, cbData );
  706.     for (i = 0; i<segCount; i++)
  707.         SwapShort (& (endCount[i]));
  708.  
  709.     /* read in the array of startCount values */
  710.     offset = offsetFormat4
  711.            + (7 * sizeof (USHORT))   /* skip constant # bytes in subtable */
  712.            + (segCount * sizeof (USHORT)) /* skip endCount array */
  713.            + sizeof (USHORT);             /* skip reservedPad */
  714.     cbData = segCount * sizeof (USHORT);
  715.     nBytes=GetFontData (hdc, CMAPHEX, offset, startCount, cbData );
  716.     for (i = 0; i<segCount; i++)
  717.         SwapShort (& (startCount[i]));
  718.  
  719.  
  720.     return segCount;
  721. }
  722.  
  723.  
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732. VOID SwapShort (PUSHORT p)
  733. {
  734. SHORT temp;
  735.  
  736.     temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8));
  737.     *p = temp;
  738. }
  739.  
  740.  
  741.  
  742. VOID SwapULong (PULONG p)
  743. {
  744. ULONG temp;
  745.  
  746.     temp = (LONG) ((BYTE) *p);
  747.     temp <<= 8;
  748.     *p >>=8;
  749.  
  750.     temp += (LONG) ((BYTE) *p);
  751.     temp <<= 8;
  752.     *p >>=8;
  753.  
  754.     temp += (LONG) ((BYTE) *p);
  755.     temp <<= 8;
  756.     *p >>=8;
  757.  
  758.     temp += (LONG) ((BYTE) *p);
  759.     *p = temp;
  760. }
  761.